/*
 * graph2D
 * Copyright (c) 2009 Shun Moriya <shun@mnu.sakura.ne.jp>
 *
 * The MIT License
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#if !defined(___GRAPHC2D_PROFILE_H___)
#define ___GRAPHC2D_PROFILE_H___

#define GRAPH2D_USE_MEMORY_GAUGE

#include "graphicDevice.h"

namespace Graph2D
{
	class Profile
	{
		DISALLOW_COPY_AND_ASSIGN(Profile);

	public:
		typedef enum Category
		{
			UPDATE = 0,
			TYPE_1,
			TYPE_2,
			TYPE_3,
			TYPE_4,
			TYPE_5,
			DRAW,
			SYNC,
			SIZE_OF_CATEGORIES
		}Category;

	private:
		typedef struct Thread
		{
			double startFrame;
			double start[SIZE_OF_CATEGORIES];
			double ticks[SIZE_OF_CATEGORIES];
		}Thread;

		typedef struct Memory
		{
			size_t totalSize;
			size_t allocatedSize;
			size_t maxFreeSize;
			size_t totalFreeSize;
		}Memory;

		static const int H_MARGIN = 3;
		static const int V_MARGIN = 8;
		static const int WIDTH = 2;

		float fps;
		float baseFPS;
		float scale;
		Thread profile[2];
		Memory memory[2];
		unsigned char profileIndex;

	private:
		Profile();

	public:
		~Profile();

		static Profile& getInstance();

		void setBaseFPS(const unsigned int baseFPS);
		double tick(const Category category) const;
		double load() const;

		void begin(const Category category);
		void end(const Category category);

		void setTotalSize(const size_t size);
		void setAllocatedSize(const size_t size);
		void setMaxFreeSize(const size_t size);
		void setTotalFreeSize(const size_t size);

		void sync();
		void draw();

	private:
		void setFPS(const double msec);
	};
}

#if (defined(DEBUG) || defined(_DEBUG) || defined(_DEBUG_)) || !defined(NDEBUG)
#define PROFILE_BEGIN(CATEGORY)				Graph2D::Profile::getInstance().begin(CATEGORY)
#define PROFILE_END(CATEGORY)				Graph2D::Profile::getInstance().end(CATEGORY)
#define PROFILE_SET_BASE_FPS(FPS)			Graph2D::Profile::getInstance().setBaseFPS(FPS)
#define PROFILE_TICK(CATEGORY)				Graph2D::Profile::getInstance().tick(CATEGORY)
#define PROFILE_LOAD(CATEGORY)				Graph2D::Profile::getInstance().load(CATEGORY)
#define PROFILE_SYNC()						Graph2D::Profile::getInstance().sync()
#define PROFILE_DRAW()						Graph2D::Profile::getInstance().draw()

#define PROFILE_SET_TOTAL_SIZE(SIZE)		Graph2D::Profile::getInstance().setTotalSize(SIZE)
#define PROFILE_SET_ALLOCATED_SIZE(SIZE)	Graph2D::Profile::getInstance().setAllocatedSize(SIZE)
#define PROFILE_SET_MAX_FREE_SIZE(SIZE)		Graph2D::Profile::getInstance().setMaxFreeSize(SIZE)
#define PROFILE_SET_TOTAL_FREE_SIZE(SIZE)	Graph2D::Profile::getInstance().setTotalFreeSize(SIZE)
#else
#define PROFILE_BEGIN(CATEGORY)				((void)0)
#define PROFILE_END(CATEGORY)				((void)0)
#define PROFILE_SET_BASE_FPS(FPS)			((void)0)
#define PROFILE_TICK(CATEGORY)				0
#define PROFILE_LOAD(CATEGORY)				0
#define PROFILE_SYNC()						((void)0)
#define PROFILE_DRAW()						((void)0)

#define PROFILE_SET_TOTAL_SIZE(SIZE)		((void)0)
#define PROFILE_SET_ALLOCATED_SIZE(SIZE)	((void)0)
#define PROFILE_SET_MAX_FREE_SIZE(SIZE)		((void)0)
#define PROFILE_SET_TOTAL_FREE_SIZE(SIZE)	((void)0)
#endif

#endif
